import {app, BrowserWindow, dialog, ipcMain, Menu, shell} from "electron";
import {join, parse} from "path";
import {electronApp, is, optimizer} from "@electron-toolkit/utils";
import icon from "../../resources/icon.png?asset";
import winIcon from "../../resources/icon.ico?asset";
import {print} from "pdf-to-printer";

import {extMap} from '../common/constants'

import fs, {existsSync} from "node:fs";
import os from "node:os";
import event from 'node:events'

import {db, initDb, log} from './db'
import {excelToPdf, pptToPdf, wordToPdf} from "./dllApp";
import {getId} from "../common/util/idUtl";
import {readFileSync} from "fs";

const resourcePath = join(__dirname, '../../resources').replace('app.asar', 'app.asar.unpacked')

const tabltBarBackground = "#83AFA1"

const tempDir = fs.mkdtempSync(join(os.tmpdir(), 'gagamengprinter-'));

console.log(`临时文件夹地址：${tempDir}`)

require("module").globalPaths.push(process.cwd() + '/node_modules');

const emiter = new event.EventEmitter()

let mainWindow: BrowserWindow;
const additionalData = process.argv
const gotTheLock = app.requestSingleInstanceLock(additionalData)

function addLog(str) {
  log.addLog(str)
}

if (!gotTheLock) {
  app.quit()
} else {
  app.on('second-instance', (event, commandLine, workingDirectory, additionalData) => {
    // 输出从第二个实例中接收到的数据

    if (!mainWindow.isVisible() && !mainWindow.isMinimized()) {
      mainWindow.once('ready-to-show', e => {
        if (additionalData.length > 2) {
          const type = additionalData[1]
          const filePath = additionalData[2]
          if (type == 'addItems') {
            addItems([filePath])
          }
        }
      })
    } else {
      if (additionalData.length > 2) {
        const type = additionalData[1]
        const filePath = additionalData[2]
        if (type == 'addItems') {
          addItems([filePath])
        }
      }
    }


    // 有人试图运行第二个实例，我们应该关注我们的窗口
    if (mainWindow) {
      if (mainWindow.isMinimized()) mainWindow.restore()
      mainWindow.focus()
    }
  })
}

function createWindow(): void {
  const size = db.data.winOpt.size || {}
  const position = db.data.winOpt.position

  // Create the browser window.
  mainWindow = new BrowserWindow({
    width: size.width || 900,
    height: size.height || 670,
    minHeight: 606,
    minWidth: 900,
    show: false,
    title: "嘎嘎猛打印",
    autoHideMenuBar: true,
    titleBarStyle: "hidden",
    titleBarOverlay: {
      color: tabltBarBackground,
      symbolColor: "#fff",
      height: 40,
    },
    ...(process.platform === "linux" ? {icon} : {icon: winIcon}),
    webPreferences: {
      webSecurity: true,
      defaultEncoding: "UTF-8",
      preload: join(__dirname, "../preload/index.js"),
      sandbox: false,
    },
  });
  if (position) {
    mainWindow.setPosition(position.x, position.y)
  }

  mainWindow.on("ready-to-show", () => {
    if (additionalData.length > 2) {
      const type = additionalData[1]
      const filePath = additionalData[2]
      if (type == 'addItems') {
        addItems([filePath])
      }
    }
    mainWindow.show();
  });

  mainWindow.webContents.setWindowOpenHandler((details) => {
    shell.openExternal(details.url);
    return {action: "deny"};
  });

  mainWindow.on('resized', () => {
    const [width, height] = mainWindow.getSize()
    db.update(({winOpt: {size}}) => {
      size.width = width
      size.height = height
    })
  })
  mainWindow.on("moved", () => {
    const [x, y] = mainWindow.getPosition()
    db.update(({winOpt}) => {
      const position = winOpt.position
      if (!position) {
        winOpt.position = {
          x: x,
          y: y
        }
      } else {
        position.x = x
        position.y = y
      }
    })
  })

  const url = "/src/pages/home/index.html"
  if (is.dev && process.env["ELECTRON_RENDERER_URL"]) {
    mainWindow.loadURL(
      process.env["ELECTRON_RENDERER_URL"] + url,
    );
  } else {
    mainWindow.loadFile(
      join(__dirname, "../renderer" + url),
    );
  }
}

let settingWindow: BrowserWindow;

function createSettingWindow(): void {
  // Create the browser window.
  settingWindow = new BrowserWindow({
    parent: mainWindow,
    modal: true,
    width: 280,
    height: 295,
    title: "设置",
    resizable: false,
    minimizable: false,
    maximizable: false,
    show: false,
    autoHideMenuBar: true,
    titleBarStyle: "hidden",
    titleBarOverlay: {
      color: tabltBarBackground,
      symbolColor: "#fff",
      height: 30,
    },
    ...(process.platform === "linux" ? {icon} : {icon: winIcon}),
    webPreferences: {
      webSecurity: true,
      defaultEncoding: "UTF-8",
      preload: join(__dirname, "../preload/setting.js"),
      sandbox: false,
    },
  });

  settingWindow.on("ready-to-show", () => {
    settingWindow.show();
  });

  settingWindow.webContents.setWindowOpenHandler((details) => {
    shell.openExternal(details.url);
    return {action: "deny"};
  });

  // HMR for renderer base on electron-vite cli.
  // Load the remote URL for development or the local html file for production.
  const url = "/src/pages/setting/index.html"
  if (is.dev && process.env["ELECTRON_RENDERER_URL"]) {
    settingWindow.loadURL(
      process.env["ELECTRON_RENDERER_URL"] + url,
    );
  } else {
    settingWindow.loadFile(
      join(__dirname, "../renderer" + url),
    );
  }
}

let messageWindow: BrowserWindow;

function createMessageWindow(option): void {
  // Create the browser window.
  const width = option.size?.width || 349
  const height = option.size?.height || 228
  messageWindow = new BrowserWindow({
    parent: mainWindow,
    modal: true,
    width: width,
    height: height,
    resizable: false,
    minimizable: false,
    maximizable: false,
    show: false,
    autoHideMenuBar: true,
    titleBarStyle: "hidden",
    titleBarOverlay: {
      color: tabltBarBackground,
      symbolColor: "#fff",
      height: 30,
    },
    ...(process.platform === "linux" ? {icon} : {icon: winIcon}),
    webPreferences: {
      webSecurity: true,
      defaultEncoding: "UTF-8",
      preload: join(__dirname, "../preload/message.js"),
      sandbox: false,
    },
  });

  ipcMain.once("confirm" + option.id, (e) => {
    emiter.emit("result" + option.id, true)
    messageWindow.close()
  })
  ipcMain.once("cancel" + option.id, (e) => {
    emiter.emit("result" + option.id, false)
    messageWindow.close()
  })

  messageWindow.on("closed", () => {
    emiter.emit("result" + option.id, false)
  })

  messageWindow.on("ready-to-show", () => {
    messageWindow.show();
  });

  messageWindow.webContents.setWindowOpenHandler((details) => {
    shell.openExternal(details.url);
    return {action: "deny"};
  });

  // HMR for renderer base on electron-vite cli.
  // Load the remote URL for development or the local html file for production.
  const msg = JSON.stringify(option)
  const url = "/src/pages/message/index.html"

  if (is.dev && process.env["ELECTRON_RENDERER_URL"]) {
    messageWindow.loadURL(process.env["ELECTRON_RENDERER_URL"] + url + "?msg=" + encodeURIComponent(msg));
  } else {
    messageWindow.loadFile(join(__dirname, "../renderer" + url), {query: {msg}});
  }
}

let previewWindow: BrowserWindow;

function createPreviewWindow(path: string): void {
  // Create the browser window.
  previewWindow = new BrowserWindow({
    parent: mainWindow,
    modal: true,
    width: 900,
    height: 670,
    title: "预览",
    resizable: false,
    minimizable: false,
    maximizable: false,
    show: false,
    autoHideMenuBar: true,
    titleBarStyle: "hidden",
    titleBarOverlay: {
      color: tabltBarBackground,
      symbolColor: "#fff",
      height: 30,
    },
    ...(process.platform === "linux" ? {icon} : {icon: winIcon}),
    webPreferences: {
      allowRunningInsecureContent: true,
      webSecurity: false,
      defaultEncoding: "UTF-8",
      preload: join(__dirname, "../preload/preview.js"),
      sandbox: false,
    },
  });

  previewWindow.on("ready-to-show", () => {
    previewWindow.show();
  });

  previewWindow.webContents.setWindowOpenHandler((details) => {
    shell.openExternal(details.url);
    return {action: "deny"};
  });

  // HMR for renderer base on electron-vite cli.
  // Load the remote URL for development or the local html file for production.
  const url = "/src/pages/preview/index.html"
  if (is.dev && process.env["ELECTRON_RENDERER_URL"]) {
    previewWindow.loadURL(
      process.env["ELECTRON_RENDERER_URL"] + url + "?path=" + encodeURIComponent(path)
    );
  } else {
    previewWindow.loadFile(
      join(__dirname, "../renderer" + url), {query: {path}}
    );
  }
}

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.whenReady().then(async () => {
  // Set app user model id for windows
  electronApp.setAppUserModelId("com.electron");

  // Default open or close DevTools by F12 in development
  // and ignore CommandOrControl + R in production.
  // see https://github.com/alex8088/electron-toolkit/tree/master/packages/utils
  app.on("browser-window-created", (_, window) => {
    optimizer.watchWindowShortcuts(window);
  });

  await initDb()

  createWindow();

  app.on("activate", function () {
    // On macOS it's common to re-create a window in the app when the
    // dock icon is clicked and there are no other windows open.
    if (BrowserWindow.getAllWindows().length === 0) createWindow();
  });
});

// Quit when all windows are closed, except on macOS. There, it's common
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q.
app.on("window-all-closed", () => {
  if (process.platform !== "darwin") {
    app.quit();
  }
});

app.on("quit", () => {
  fs.rmSync(tempDir, {recursive: true, force: true})
})

function addItems(pathList) {
  if (!pathList) {
    return;
  }
  for (const dialogSyncElement of pathList) {
    const stats = fs.statSync(dialogSyncElement);
    if (stats.isFile()) {
      const parseObj = parse(dialogSyncElement);
      mainWindow.webContents.send("addItems", [{
        wjmc: parseObj.base,
        rq: stats.birthtime.toLocaleString(),
        wjlx: parseObj.ext,
        wjdx: bytesToSize(stats.size),
        wjjlj: parseObj.dir
      }]);
    } else if (stats.isDirectory()) {
      const dir = fs.readdirSync(dialogSyncElement).map(file => join(dialogSyncElement, file));
      addItems(dir)
    } else {
      console.log("未知文件/文件夹：" + dialogSyncElement)
    }
  }
}

ipcMain.on("printSelf", (e, option) => {
  e.sender.print(
    {
      silent: true, // 是否不向用户询问设置
      printBackground: false, // 打印网页的背景颜色和图像
      deviceName: option.dyj, // 打印设备的名称
      pageSize: option.pageSize,
      landscape: false, // 是否横向打印
      color: !option.monochrome, // 是否为彩色打印
      copies: option.copies, // 打印份数
      duplexMode: option.side, // 双面打印
      margins: {
        marginType: 'printableArea' // 可打印区域
      }
    },
    (success, failureReason) => {
      const result = {
        code: success ? 0 : 1000,
        message: !failureReason ? '已将数据发送给打印机, 请关注打印机状态。' : '打印失败'
      }
      console.log(result, failureReason)
    }
  )
});

ipcMain.on("preview", (e, path) => {
  createPreviewWindow(path);
});

ipcMain.on("addItems", (e, pathList) => {
  addItems(pathList);
});

ipcMain.on("showMessage", (e, option) => {
  emiter.once("result" + option.id, (res) => {
    e.sender.send("result" + option.id, res)
  })
  createMessageWindow(option);
});

ipcMain.on("openSetting", (e) => {
  createSettingWindow();
});

ipcMain.on("close", (e) => {
  BrowserWindow.fromWebContents(e.sender)?.close();
});

ipcMain.on("openItem", (e, path) => {
  // const encodePath = iconv.encode(path, "ascii").toString("binary")
  shell.openPath(path);
});

ipcMain.on("print", async (e, args) => {
  let error: unknown = null;
  try {
    await print(args.path, args.option);
  } catch (e) {
    error = e;
  }
  e.sender.send("result" + args.id, error);
});

ipcMain.on("getPrinters", async (e) => {
  const printers = await e.sender.getPrintersAsync();

  const printerList = [];
  for (let printer of printers) {
    printerList.push({
      dyjmc: printer.name,
      dyjxsmc: printer.displayName,
      sfmrdyj: printer.isDefault,
      dyjzt: printer.status,
    });
  }

  e.returnValue = printerList;
});
ipcMain.on("selectFile", (e) => {
  let dialogSync = dialog.showOpenDialogSync(mainWindow, {
    properties: ["openFile", "multiSelections"],
  });
  addItems(dialogSync);
});

ipcMain.on("selectFileByWjj", (e) => {
  let dirNames = dialog.showOpenDialogSync(mainWindow, {
    properties: ["openDirectory"],
  });
  addItems(dirNames);
});

const bytesToSize = (size) => {
  if (size < 1 * 1024) {
    //小于1KB，则转化成B
    size = size.toFixed(2) + "B";
  } else if (size < 1 * 1024 * 1024) {
    // 小于1MB，则转化成KB
    size = (size / 1024).toFixed(2) + "KB";
  } else if (size < 1 * 1024 * 1024 * 1024) {
    // 小于1GB，则转化成MB
    size = (size / (1024 * 1024)).toFixed(2) + "MB";
  } else {
    // 其他转化成GB
    size = (size / (1024 * 1024 * 1024)).toFixed(2) + "GB";
  }

  // 转成字符串
  let sizeStr = size + "",
    // 获取小数点处的索引
    index = sizeStr.indexOf("."),
    // 获取小数点后两位的值
    dou = sizeStr.substr(index + 1, 2);

  // 判断后两位是否为00，如果是则删除00
  if (dou == "00")
    return sizeStr.substring(0, index) + sizeStr.substr(index + 3, 2);

  return size;
};
ipcMain.on('show-context-menu', (ev, arg) => {
  const template = []
  for (let optionElement of arg.option) {
    const item = {...optionElement}
    if (optionElement.label) {
      item.click = () => ev.sender.send(optionElement.label + arg.id)
    }
    template.push(item)
  }

  const menu = Menu.buildFromTemplate(template)
  menu.popup({window: BrowserWindow.fromWebContents(ev.sender)})
})

ipcMain.on('getPrintCount', (ev) => {
  ev.returnValue = db.data.printCount || 0
})
ipcMain.on('addPrintCount', (ev, count = 0) => {
  db.update(data => {
    if (!data.printCount) {
      data.printCount = 0
    }
    data.printCount += count
  })
})
ipcMain.on('addLog', (ev, str = '') => {
  addLog(str)
})

ipcMain.on("getPrintFile", async (e, option) => {
  try {
    let pdfPath = "";
    const ext = extMap[option.path.substring(option.path.lastIndexOf(".") + 1).toLowerCase()] || 'other'
    // PDF或者图片不进行转换
    if (ext === 'pdf' || ext === 'image') {
      pdfPath = option.path
    } else {
      // 其他类型需要进行文件格式转换，转换为pdf
      // 判断目录是否存在，不存在则进行创建
      const tempPath = join(tempDir, getId(), option.path.substring(option.path.lastIndexOf("\\") + 1))
      const pathParse = parse(tempPath)
      if (!fs.existsSync(pathParse.dir)) {
        fs.mkdirSync(pathParse.dir)
      }
      // 拷贝一份文件到临时目录
      fs.copyFileSync(option.path, tempPath)
      // pdf的路径
      pdfPath = join(pathParse.dir, pathParse.name + ".pdf")
      if (ext === 'word') {
        await wordToPdf(tempPath, pdfPath)
      } else if (ext === 'excel') {
        await excelToPdf(tempPath, pdfPath)
      } else if (ext === 'ppt') {
        await pptToPdf(tempPath, pdfPath)
      } else {
        throw new Error("暂时不支持的文件类型：" + pathParse.ext)
      }
    }
    e.sender.send("result" + option.id, {printFile: pdfPath})
  } catch (e) {
    e.sender.send("result" + option.id, {error: e})
  }
});

ipcMain.on('getAppInfo', (ev) => {
  const appInfo = {version: app.getVersion()}
  const bbinfoFile = join(resourcePath, "bbinfo.json")
  if (existsSync(bbinfoFile)) {
    const dbsj = JSON.parse(readFileSync(bbinfoFile)).dbsj
    appInfo.dbsj = dbsj
  }
  const installFile = join(resourcePath, "install.txt")
  if (existsSync(installFile)) {
    const installDate = readFileSync(installFile)
    appInfo.installDate = installDate.toString()
  }
  ev.returnValue = appInfo
})